package org.gen.pojo.core;

import freemarker.template.Template;
import org.gen.pojo.config.GenConfig;
import org.gen.pojo.util.DBMetaUtil;
import org.gen.pojo.util.MavenModuleUtil;

import java.io.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by zhuge on 2017/10/15.
 */
public abstract class Generate {
	public static final Map<String, Object> root = GenConfig.configPersonal();

	/**
	 * 返回注释信息
	 *
	 * @param table_name
	 * @return
	 */

	public String getTableComment(String table_name) {
		String comment = table_name;
		;
		try {
			Connection connection = DBMetaUtil.getConnection();
			Statement stmt = connection.createStatement();
			ResultSet rs = stmt.executeQuery("SHOW CREATE TABLE " + table_name);
			if (rs != null && rs.next()) {
				String createDDL = rs.getString(2);
				comment = parse(createDDL);
			}
			System.out.println("【调试消息】：表" + table_name + "字段获取完成！");
		} catch (Exception e) {
			System.err.println("【异常消息】：表" + table_name + e.getMessage());
		}

		return comment;
	}

	private String parse(String createDDL) throws Exception {
		String comment = null;
		int index = createDDL.indexOf("COMMENT='");
		if (index < 0) {
			throw new Exception("没有注释");
		}
		comment = createDDL.substring(index + 9);
		comment = comment.substring(0, comment.length() - 1);
		return comment;
	}

	public void start() {
		try {
			// 获取数据库源数据
			DatabaseMetaData metaData = DBMetaUtil.getMetaData();
			/**
			 * 其中"%"就是表示*的意思，也就是任意所有的意思。 其中m_TableName就是要获取的数据表的名字，
			 * 如果想获取所有的表的名字，就可以使用"%"来作为参数了。 获取数据库中所有表的源数据信息
			 */
			ResultSet tableRet = metaData.getTables(null, "%", "%", new String[] { "TABLE" });
			// 提取表的名字。
			List<Attribute> attr_list = new ArrayList<>();
			while (tableRet.next()) {
				String TABLE_NAME = tableRet.getString("TABLE_NAME");
				// 将当前表的数据放到表字段属性容器中
				putTableToList(metaData, TABLE_NAME, attr_list);
				// 生成当前表的pojo
				rebuildConfigRoot(TABLE_NAME, attr_list);
				// attr_list 表字段属性容器，用完即清空
				gen();
				attr_list.clear();
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("未知异常" + e.getMessage());
		}

	}

	// protected abstract void putTableToList(DatabaseMetaData metaData, String
	// table_name, List<Attribute> attr_list);

	protected abstract void rebuildConfigRoot(String table_name, List<Attribute> attr_list);

	protected abstract void gen() throws Exception;

	public void commonGenerateFile(String packageDir, String fileName, Template template) {
		try {
			File dir = new File(GenConfig.java_source_path + packageDir);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			OutputStream fos = new FileOutputStream(new File(dir, fileName)); // java文件的生成目录
			Writer out = new OutputStreamWriter(fos);
			template.process(root, out);
			fos.flush();
			fos.close();
			// System.out.println(fileName + " has generated~ gen code success!");
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("commonGenerateFile输出异常 :" + e.getMessage());
		}

	}

	// 字符串首字母转小写
	public String UncapFirstString(String str) {
		return str.substring(0, 1).toLowerCase() + str.substring(1);
	}

	// 包名转换为路径
	public String packageToDir(String packageName) {
		return MavenModuleUtil.packageToDir(packageName);
	}

	// 把表数据放到集合中
	public void putTableToList(DatabaseMetaData dbmd, String m_TableName, List<Attribute> attr_list) {
		try {
			String columnName;
			String columnType;
			String comment;
			ResultSet colRet = dbmd.getColumns(null, "%", m_TableName, "%");
			Connection connection = dbmd.getConnection();
			Statement stmt = connection.createStatement();
			ResultSet rs = stmt.executeQuery("show full columns from " + m_TableName);
			while (rs.next() && colRet.next()) {
				// System.out.println(rs.getString("Field") + "\t:\t" +
				// rs.getString("Comment"));
				// columnName = rs.getString("Field");
				columnName = colRet.getString("COLUMN_NAME");
				columnType = colRet.getString("TYPE_NAME");
				comment = rs.getString("Comment");
				attr_list.add(new Attribute(columnName, columnNameToJavaProperty(columnName),
						jdbcTypeToJavaType(columnType), comment));
			}

			rs.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	// 判断是否包含日期
	protected boolean hasDateType(List<Attribute> attr_list) {
		for (Attribute attr : attr_list) {
			if ("Date".equals(attr.getType())) {
				return true;
			}
		}
		return false;
	}

	// 将表名转换为java类名，规则即去掉下划线，将首字符大写
	protected String tableNameToClassName(String tablename) {
		String[] split = tablename.split("_");
		StringBuilder ret = new StringBuilder();
		for (String str : split) {
			// if("tb".equals(str)){
			// continue;
			// }
			// 首字母变大写
			str = str.substring(0, 1).toUpperCase() + str.substring(1);
			// 拼接到一起作为类名
			ret.append(str);
		}
		return ret.toString();
	}

	// 将列名转换为java属性名，规则即去掉下划线，将第一个单词全小写,其他每个单词首字符大写，
	protected static String columnNameToJavaProperty(String columnName) {
		// province_id
		String[] split = columnName.split("_");
		StringBuilder ret = new StringBuilder();
		for (String str : split) {
			// 首字母变大写
			str = str.substring(0, 1).toUpperCase() + str.substring(1);
			// 拼接到一起作为类名
			ret.append(str);
		}
		String javaProperty = ret.toString();
		return javaProperty.substring(0, 1).toLowerCase() + javaProperty.substring(1);

	}

	// 数据库类型和java类型的转换
	protected String jdbcTypeToJavaType(String jdbcType) {
		return mysqlDict().get(jdbcType.toUpperCase());
	}

	private static Map<String, String> mysqlDict() {
		Map<String, String> dict = new HashMap<>();
		dict.put("VARCHAR", "String");
		dict.put("BIGINT", "Long");
		dict.put("VARCHAR", "String");
		dict.put("INT", "Integer");
		dict.put("DECIMAL", "Double");
		dict.put("DATETIME", "Date");
		return dict;
	}

}